﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net.Sockets;
using System.Net;

namespace WpfSocketServer
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.readBuffer = new byte[16];

            listener = new TcpListener(IPAddress.Any, 4502);
            listener.Start(5);
            connectedClients = new List<TcpClient>();
            BeginAcceptSocket();
        }

        void BeginAcceptSocket()
        {
            listener.BeginAcceptSocket(OnAcceptSocket, null);
        }

        void OnAcceptSocket(IAsyncResult result)
        {
            Socket acceptedSocket = listener.EndAcceptSocket(result);

            lock (connectedClients)
            {
                TcpClient client = new TcpClient()
                {
                    Client = acceptedSocket
                };
                connectedClients.Add(client);

                BeginRead(client);
            }
            BeginAcceptSocket();
        }

        void BeginRead(TcpClient client)
        {
            client.GetStream().BeginRead(
                this.readBuffer,
                bufferUsed,
                this.readBuffer.Length - bufferUsed,
                OnReadCompleted,
                client);
        }

        void MoveCircle(Point point)
        {
            Dispatcher.BeginInvoke(new Action(() =>
                {
                    circle.Margin = new Thickness(
                        point.X - (circle.Width/2),
                        point.Y - (circle.Height)/2,
                        mainGrid.ActualWidth - (point.X + circle.Width),
                        mainGrid.ActualHeight - (point.Y + circle.Height));
                }));
        }

        void OnReadCompleted(IAsyncResult result)
        {
            TcpClient client = (TcpClient)result.AsyncState;
            try
            {
                int bytesRead = client.GetStream().EndRead(result);

                if (bufferUsed+bytesRead==readBuffer.Length)
                {
                    bufferUsed = 0;
                    Point point = PointExt.FromBuffer(readBuffer);
                    MoveCircle(point);
                }
                else
                {
                    bufferUsed += bytesRead;
                }
                BeginRead(client);
            }
            catch (Exception ex)
            {
                client.Close();

                lock (this.connectedClients)
                {
                    this.connectedClients.Remove(client);
                }
            }
        }

        void OnMouseMove(object sender, MouseEventArgs args)
        {
            Point point = args.GetPosition(mainGrid);
            MoveCircle(point);

            List<TcpClient> clients = null;

            lock (connectedClients)
            {
                clients = new List<TcpClient>(connectedClients);
            }
            foreach (TcpClient client in clients)
            {
                NetworkStream stream = client.GetStream();

                byte[] bits = PointExt.ToBuffer(point);
                stream.Write(bits,0,bits.Length);
                stream.Flush();
            }
        }

        byte[] readBuffer;
        int bufferUsed;
        TcpListener listener;
        List<TcpClient> connectedClients;
    }
}
